from shelve2 import Persistent, lazy
from os import listdir, mkdir, remove, rmdir
from os.path import abspath, dirname, exists, join as path_join

class Anonymous(Persistent):
	@property
	def filename(self):
		return str(self)

	def _p_initialize(self, conn=None):
		Persistent._p_initialize(self, conn)

		filename = self._p_conn.filename
		base = path_join(abspath(dirname(filename)),
			'%s.anonymous' %filename)

		uuid = uuid4()
		p1 = path_join(base, uuid[:2])
		p2 = path_join(p1, uuid[2:4])
		if not exists(base):
			self._p_filename = ((base, p1, p2), path_join(p2, uuid[4:]))
			self.uuid = uuid
			return

		for i in xrange(20):
			uuid = uuid4()
			p1 = path_join(base, uuid[:2])
			p2 = path_join(p1, uuid[2:4])
			p3 = path_join(p2, uuid[4:])
			if exists(p1):
				if exists(p2):
					if exists(p3):
						continue
					else:
						self._p_filename = p3
						self.uuid = uuid
						break
				else:
					self._p_filename = ((p2, ), p3)
					self.uuid = uuid
					break
			else:
				self._p_filename = ((p1, p2), p3)
				self.uuid = uuid
				break
		try:
			if self.uuid:
				return
		except AttributeError:
			raise RuntimeError('generate uuid faild')

	def __str__(self):
		filename = self._p_conn.filename
		base = path_join(abspath(dirname(filename)),
			'%s.anonymous' %filename)

		uuid = self.uuid
		return path_join(base, uuid[:2], uuid[2:4], uuid[4:])

	def __repr__(self):
		return '<anonymous file at "%s">' %str(self)

	def _p_release(self):
		Persistent._p_release(self)
		filename = self._p_conn.filename
		base = path_join(abspath(dirname(filename)),
			'%s.anonymous' %filename)

		uuid = self.uuid
		p1 = path_join(base, uuid[:2])
		p2 = path_join(p1, uuid[2:4])
		p3 = path_join(p2, uuid[4:])
		if not exists(p3):
			return

		remove(p3)
		for i in (p2, p1, base):
			try:
				rmdir(i)
			except OSError, e:
				if e.errno == 39:
					return
				raise

	def open(self, method, mode='r'):
		try:
			filename = self._p_filename
		except AttributeError:
			filename = self._p_conn.filename
			base = path_join(abspath(dirname(filename)),
				'%s.anonymous' %filename)

			uuid = self.uuid
			p1 = path_join(base, uuid[:2])
			p2 = path_join(p1, uuid[2:4])
			if not exists(base):
				filename = ((base, p1, p2), path_join(p2, uuid[4:]))
			elif not exists(p1):
				filename = ((p1, p2), path_join(p2, uuid[4:]))
			elif not exists(p2):
				filename = ((p2, ), path_join(p2, uuid[4:]))
			else:
				filename = path_join(p2, uuid[4:])

		if isinstance(filename, tuple):
			for i in filename[0]:
				mkdir(i)

			return method(filename[1], mode)
		return method(filename, mode)

try:
	from os import urandom
	urandom(16)

except NotImplementedError:
	from random import randrange
	def uuid4():
		n = long(fmt % tuple(randrange(256) for i in range16))
		n &= n1; n |= n2; n &= n3; n |= n4
		return '%032x' % n
else:
	def uuid4():
		n = long(fmt % tuple(map(ord, urandom(16))), 16)
		n &= n1; n |= n2; n &= n3; n |= n4
		return '%032x' % n

range16 = '\x00' * 16; fmt = '%02x' * 16
n1 = ~(0xc000 << 48L); n2 = 0x8000 << 48L
n3 = ~(0xf000 << 64L); n4 = 4 << 76L

File = Anonymous
